﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Conversion_Script
{
    class LandUseTransitions
    {
        static Random rnd = new Random();
        static float[,] cumtransitionprobabilities;
        public static float[,] CumTransitionprobabilities
        {
            get
            {
                return cumtransitionprobabilities;
            }
        }
        static float[,] transitionprobabilities;
        public static float[,] Transitionprobabilities
        {
            get
            {
                return transitionprobabilities;
            }
        }
        public static void Initialize()
        {
            cumtransitionprobabilities = new float[Landscape.LandUseNames.Length, Landscape.LandUseNames.Length];
            transitionprobabilities = new float[Landscape.LandUseNames.Length, Landscape.LandUseNames.Length];

            for (int from_landuse = 0; from_landuse < Landscape.LandUseNames.Length; from_landuse++)
            {
                float p = 0;
                for (int to_landuse = 0; to_landuse < Landscape.LandUseNames.Length; to_landuse++)
                {
                    p = float.Parse(CO2FixSimulations.Landuse.GetValue(Landscape.LandUseNames[from_landuse], Landscape.LandUseNames[to_landuse]));
                    cumtransitionprobabilities[from_landuse, to_landuse] += p;
                    transitionprobabilities[from_landuse, to_landuse] = p;
                }

            }
        }
        
        private static int[,] GetTransitionsPerLandUse()
        {
            int[] LUsums = Landscape.LandUseMap.GetFrequency();

            int[,] TransitionsPerLandUse = new int[Landscape.LandUseNames.Length,Landscape.LandUseNames.Length];

            for (int from = 0; from < Landscape.LandUseNames.Length; from++)
            { 
                for (int to = 0; to < Landscape.LandUseNames.Length; to++)
                {
                    if (from == to) continue;
                    TransitionsPerLandUse[from, to] = (int)(Transitionprobabilities[from, to] * LUsums[from]);
                    float remnant = Transitionprobabilities[from, to] * LUsums[from] - TransitionsPerLandUse[from, to];
                    if (rnd.NextDouble() < remnant) TransitionsPerLandUse[from, to]++;
                }
            }
            return TransitionsPerLandUse;
        }
        static bool IsGoodDonatingSite(int r, int c, int DonatingLandUseType)
        {
            try
            {
                if (r < 0 || c < 0 || r >= Landscape.LandUseMap.Nrows || c >= Landscape.LandUseMap.Ncols)
                {
                    //Console.WriteLine("site [" + r + "," + c + "] is off the map");
                    return false;
                }
                if (Landscape.LandUseMap[r, c] == DonatingLandUseType)
                {
                    //Console.WriteLine("Found donating site");
                    return true;
                }
                return false;
            }
            catch(System.Exception e)
            {
                throw new System.Exception("IsGoodDonatingSite " + e.Message);
            }
        }
        public static void ImplementLandUseTransition()
        {
            try
            {
                int[] LandUseSum = Landscape.LandUseMap.GetFrequency();

              
                int[,] TransitionsPerLandUse = GetTransitionsPerLandUse();
              
                for (int from = 0; from < Landscape.LandUseNames.Length; from++)
                {
                    for (int to = 0; to < Landscape.LandUseNames.Length; to++)
                    { 
                        int Transitions = TransitionsPerLandUse[from,to];

                        if(Transitions > LandUseSum[from])
                        {
                            Transitions = LandUseSum[from];
//                            throw new System.Exception("Cannot convert " + Transitions + " from " + Landscape.LandUseNames[from] + " to " + Landscape.LandUseNames[to]);
                        }

                        int t = 0;
                        
                        while (t < Transitions)
                        {
                            int r_to = rnd.Next(Landscape.LandUseMap.Nrows);
                            int c_to = rnd.Next(Landscape.LandUseMap.Ncols);

                            // to: will be connected (settlement), not target ls!!
                            if (Landscape.LandUseNames[Landscape.LandUseMap[r_to, c_to]].Contains("Settlement"))
                            {
                                int r_from;
                                int c_from;
                                //Console.WriteLine("Found " + LandUseDefininitions.LandUseTypes[to] + " in [" + r_to + "," + c_to + "]...looking for " + LandUseDefininitions.LandUseTypes[from]);
                                for (; ; ) 
                                {
                                    int d = 1;
                                    bool FoundTo = false;
                                    for (;;)
                                    {
                                        // Right bottom
                                        r_from = r_to + d;
                                        c_from = c_to + d;
                                        if (IsGoodDonatingSite(r_from,c_from,from))
                                        {
                                           FoundTo = true;
                                           break;
                                        }
                                        if (FoundTo == true) break;
                                        for (int c = 0; c < 2 * d; c++)
                                        {
                                            c_from --;
                                            if (IsGoodDonatingSite(r_from, c_from, from))
                                            {
                                                FoundTo = true;
                                                break;
                                            }
                                            if (FoundTo == true) break;
                                        }
                                        if (FoundTo == true) break;
                                        for (int r = 0; r < 2 * d; r++)
                                        {
                                            r_from --;
                                            if (IsGoodDonatingSite(r_from, c_from, from))
                                            {
                                                FoundTo = true;
                                                break;
                                            }
                                            if (FoundTo == true) break;
                                        }
                                        if (FoundTo == true) break;
                                        for (int c = 0; c < 2 * d; c++)
                                        {
                                            c_from ++;
                                            if (IsGoodDonatingSite(r_from, c_from, from))
                                            {
                                                FoundTo = true;
                                                break;
                                            }
                                            if (FoundTo == true) break;
                                        }
                                        if (FoundTo == true) break;
                                        for (int r = 0; r < 2 * d; r++)
                                        {
                                            r_from ++;
                                            if (IsGoodDonatingSite(r_from, c_from, from))
                                            {
                                                FoundTo = true;
                                                break;
                                            }
                                            if (FoundTo == true) break;
                                        }
                                        if (FoundTo == true) break;
                                        else d++;
                                        
                                    }
                                    if (FoundTo)
                                    {
                                        //Console.WriteLine("Found donating landuse in [" + r_from + "," + c_from + "]");
                                        break;
                                    }
                                    
                                }
                                //Console.WriteLine("Changing   [" + r_from + "," + c_from + "] from " + LandUseDefininitions.LandUseTypes[Landscape.LandUse[r_from, c_from]] + " to " + LandUseDefininitions.LandUseTypes[to]);
                                Landscape.LandUseMap[r_from, c_from] = to;
                                CO2FixSimulations.Co2year[r_from, c_from] = 0;
                                t++;
                            }
                            
                        
                        }
                    }
                }

                 
                 
            }
            catch (System.Exception e)
            {
                throw new System.Exception("ImplementLandUseTransition\t" + e.Message);
            }

        }

        
    }
}
